eip_onfault = 24

.global __get_user1, __put_user1
.global __get_user2, __put_user2
.global __get_user4, __put_user4
.global memcpy_from_user, memset_user
.global strlen_user, strcpy_from_user

#define USER_PREFIX \
	pushl	%ebp;  \
	movl	%esp, %ebp; \
	pushl	%ebx; \
	pushl	%ecx; \
	pushl	%edx; \
	pushl	%esi; \
	pushl	%edi; \
\
	movl	current, %ebx; \
	movl	$user_failed, eip_onfault(%ebx) 

#define USER_SUFFIX \
	movl	$0, eip_onfault(%ebx); \
	popl	%edi; \
	popl	%esi; \
	popl	%edx; \
	popl	%ecx; \
	popl	%ebx; \
	popl	%ebp; \
	ret

	.align 2
user_failed:
	movl	$0, eip_onfault(%ebx)
	movl	$-1, %eax
	popl	%edi
	popl	%esi
	popl	%edx
	popl	%ecx
	popl	%ebx
	popl	%ebp
	ret

/*
 * int __get_user1(unsigned char * dest, unsigned char * src);
 */
	.align 2
__get_user1:
	USER_PREFIX;
	movl	12(%ebp), %esi
	movl	8(%ebp), %edi
	movb	(%esi), %al
	movb	%al, (%edi)
	movl	$1, %eax
	USER_SUFFIX;

/*
 * int __put_user1(unsigned char * dest, unsigned char x);
 */
	.align 2
__put_user1:
	USER_PREFIX;
	movb	12(%ebp), %al
	movl	8(%ebp), %edi
	movb	%al, (%edi)
	movl	$1, %eax
	USER_SUFFIX;

/*
 * int __get_user2(unsigned short * dest, unsigned short * src);
 */
	.align 2
__get_user2:
	USER_PREFIX;
	movl	12(%ebp), %esi
	movl	8(%ebp), %edi
	movw	(%esi), %ax
	movw	%ax, (%edi)
	movl	$2, %eax
	USER_SUFFIX;

/*
 * int __put_user2(unsigned short * dest, unsigned short x);
 */
	.align 2
__put_user2:
	USER_PREFIX;
	movw	12(%ebp), %ax
	movl	8(%ebp), %edi
	movw	%ax, (%edi)
	movl	$2, %eax
	USER_SUFFIX;

/*
 * int __get_user4(unsigned long * dest, unsigned long * src);
 */
	.align 2
__get_user4:
	USER_PREFIX;
	movl	12(%ebp), %esi
	movl	8(%ebp), %edi
	movl	(%esi), %eax
	movl	%eax, (%edi)
	movl	$4, %eax
	USER_SUFFIX;

/*
 * int __put_user4(unsigned long * dest, unsigned long x);
 */
	.align 2
__put_user4:
	USER_PREFIX;
	movl	12(%ebp), %eax
	movl	8(%ebp), %edi
	movl	%eax, (%edi)
	movl	$4, %eax
	USER_SUFFIX;

/*
 * int memcpy_from_user(void * dest, const void * src, int n);
 */
	.align 2
memcpy_from_user:
	USER_PREFIX;
	movl	16(%ebp), %ecx
	movl	12(%ebp), %esi
	movl	8(%ebp), %edi
	cld
	movl	%ecx, %edx
	shr	$2, %ecx
	rep
	movsl
	testb	$2, %dl
	je	1f
	movsw
1:
	testb	$1, %dl
	je	2f
	movsb
2:
	movl	%edx, %eax
	USER_SUFFIX;

/*
 * int memset_user(void * dest, int ch, int n);
 */
	.align 2
memset_user:
	USER_PREFIX;
	movl	16(%ebp), %ecx
	movb	12(%ebp), %al
	movl	8(%ebp), %edi
	cld
	movb	%al, %ah
	pushw	%ax
	shl	$16, %eax
	popw	%ax
	movl	%ecx, %edx
	shr	$2, %ecx
	rep
	stosl
	testb	$2, %dl
	je	1f
	stosw
1:
	testb	$1, %dl
	je	2f
	stosb
2:
	movl	%edx, %eax
	USER_SUFFIX;

/*
 * int strlen_user(const char * str);
 */
	.align 2
strlen_user:
	USER_PREFIX;
	movl	8(%ebp), %edi
	cld
	xor	%eax, %eax
	movl	$0xffffffff, %ecx
	movl	$0xfffffffe, %edx
	repne
	scasb
	subl	%ecx, %edx
	movl	%edx, %eax
	USER_SUFFIX;
	
/*
 * char * strcpy_from_user(char * dest, const char * src);
 */
	.align 2
strcpy_from_user:
	USER_PREFIX;
	movl	12(%ebp), %esi
	movl	8(%ebp), %edi
	cld
1:
	lodsb
	stosb
	testb	%al, %al
	jne	1b
	movl	8(%ebp), %eax
	USER_SUFFIX
